package com.iceland.common.rpc;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MarkerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;

@Slf4j
public class RemoteMethodInvocationHandler implements InvocationHandler {


    private Class interfaceClass;
    private String path;
    private RpcMessageManager rpcMessageManager;

    public String getPath() {
        return path;
    }


    public RemoteMethodInvocationHandler(Class interfaceClass, RpcMessageManager rpcMessageManager) throws Exception {

        this.interfaceClass = interfaceClass;
        this.rpcMessageManager=rpcMessageManager;
        Annotation annotation = interfaceClass.getAnnotation(RemoteService.class);
        if (annotation==null){
            throw new Exception(interfaceClass+"不存在@RemoteService,不能为该接口创建代理对象");
        }
        RemoteService remoteService=(RemoteService) annotation;
        path = remoteService.path();

    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //封装请求
        RpcRequest request=new RpcRequest();
        request.setParameters(args);
        request.setMethod(method.getName());
        request.setPath(path);
        request.setRequestId(UUID.randomUUID().toString());
        log.debug(MarkerFactory.getMarker(this.getClass().getTypeName()),"调用客户端远程方法阻塞中,{}.{}(),path:{}",interfaceClass.getTypeName(),method.getName(),request.getPath());
        //同步方式请求调用
        RpcResponse response = rpcMessageManager.request(request);
        if(response.getRpcStatus().equals(RpcStatusEnum.ERROR)){
            log.error(MarkerFactory.getMarker(this.getClass().getTypeName()),"响应错误，远程方法执行出错,id:{},异常信息:{}",response.getRequestId(),response.getException());
            throw new Exception(response.getException());
        }
        log.debug(MarkerFactory.getMarker(this.getClass().getTypeName()),"调用客户端远程方法成功,id:{}",response.getRequestId());
        return response.getReturnValue();
    }

    public <T> T getProxy(){
        return (T)Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass},this);

    }

}
